package prog.model;



import java.io.*;
import java.net.*;
import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/**
 *
 * @author MrKhoai
 */
public class Resource extends Data {
    private URL location = null;
    private URL home = null;
    private StringBuffer content = null;
    private ArrayList<Resource> srcList = null;
    private ArrayList<HtmlPage> subLinks = null;

    public Resource(String url) throws MalformedURLException {
        location = new URL(url);
        home = new URL(location.getProtocol() + "://" + location.getHost() + '/');
    }

    public Resource(URL url) throws MalformedURLException{
        location = url;
        home = new URL(location.getProtocol() + "://" + location.getHost() + '/');
    }

    public InputStream getResource() throws IOException {
        BufferedInputStream reader = new BufferedInputStream(
                                     location.openStream());
        return reader;
    }

    public void download(String dst) {
        writeToFile(dst);
    }

    public String getURL() {
        return location.toString();
    }

    public String toString() {
        return location.toString();
    }


    public String getURLandUpdate(String stuffTag){
        String value = getValue(stuffTag);
        //System.out.println("value: " + _url);

        String _url = value;
        String newValue = "";
        if(_url.startsWith("http://")) {
            newValue = _url;
            newValue = newValue.replaceFirst("http://", "../");
        }
        else
        if(_url.startsWith("/")) {
            _url = _url.replaceFirst("/", "");
            newValue = _url;
            _url = home.toString() + _url;
        }
        else {
            newValue = _url;
            _url = home.toString() + _url;
        }

        updateContent(value,newValue);
        return _url;
    }

     public String getValue(String stuffTag){
        String value = "";

        int begin = stuffTag.indexOf('"');
        int end = stuffTag.lastIndexOf('"');
        if(begin == -1 || end == -1){
            begin = stuffTag.indexOf("'");
            end = stuffTag.lastIndexOf("'");
            if(begin == -1 || end == -1){
                begin = stuffTag.indexOf("(");
                end = stuffTag.lastIndexOf(")");
            }
        }
        if(begin + 1 >= end || begin == -1){
            return value;
        }

        //System.out.println(stuffTag + "begin = " + begin + "end = " + end);
        value = stuffTag.substring(begin + 1, end);
        if(value.trim().equals(""))
            return "";
        return value;
    }

    public String getFullPath(String dst){
        String fullPath = null;

        String host = location.getHost();
        String path = location.getFile();

        if(!dst.endsWith("/")) {
            dst += '/';
        }

        if(path.equals("") || path.equals("/")) {
            File ff = new File(dst + host);
            if(!ff.exists()) {
                ff.mkdirs();
            }
        } else{
            path = path.replace('?', '@');
            path = path.replace('\\', '@');
            path = path.replace(':', '@');
            path = path.replace('*', '@');
            path = path.replace('<', '@');
            path = path.replace('>', '@');
            path = path.replace('|', '@');

            fullPath = dst + host + path;
            int index = fullPath.lastIndexOf('/');
            if(index != -1) {
                File ff = new File(fullPath.substring(0, index));
                if(!ff.exists()) {
                    ff.mkdirs();
                }
            }
        }

        return fullPath;
    }

    public String getFileExtension(){
        String fileExtension = null;

        String temp = location.getFile();
        int nIndex = temp.lastIndexOf('.');
        if(nIndex != - 1)
            fileExtension = temp.substring(nIndex + 1);
        else
            fileExtension = null;

        return fileExtension;
    }

    public StringBuffer getContent(BufferedInputStream in) throws IOException{
        StringBuffer buffer = new StringBuffer();
        String line = null;
        byte[] bytes = new byte[1024];
        int nbyte = in.read(bytes, 0, bytes.length);
        while(nbyte != -1) {
            line = new String(bytes, 0, nbyte);
            buffer.append(line);//System.out.println(line);
            nbyte = in.read(bytes);
        }
        return buffer;
    }

    public void updateContent(String value, String newValue){
        Pattern pattern = Pattern.compile(value);
        Matcher matcher = pattern.matcher(content);
        content = new StringBuffer(matcher.replaceAll(newValue));
    }

    public ArrayList<String> getStringMatch(String regex, String source){
        ArrayList<String> strMatch = new ArrayList<String>();
        try{
            Pattern pattern = Pattern.compile(regex);
            Matcher matcher = pattern.matcher(source);
            while (matcher.find()) {
                strMatch.add(matcher.group());
            }
        }catch(PatternSyntaxException pse){
            //pse processing.
        }
        return strMatch;
    }

    public ArrayList<Resource> getSubResources(String fileExtension) throws MalformedURLException{
        ArrayList<Resource> subResources = new ArrayList<Resource>();
        if(content == null)
            return subResources;

        String regex = null;
        if(fileExtension.equalsIgnoreCase("css")){
            regex = "url\\(['\\\"]*[^')]+['\\\"]*\\)";
        }else if(fileExtension.equalsIgnoreCase("js")){
            regex = "src\\s*=\\s*(\'|\")(.*?)(\'|\")";
        }else
            return subResources;
        ArrayList<String> candidate = getStringMatch(regex, content.toString());

        for(String str: candidate){
            //System.out.println("Sublink: " + str);
            String url = getURLandUpdate(str);
            Resource src = new Resource(url);
            subResources.add(src);
            //System.out.println("Sublink: " + src.getURL());
        }

        return subResources;
    }

    public ArrayList<HtmlPage> getSubLinks(String fileExtension){
        ArrayList<HtmlPage> subLink = new ArrayList<HtmlPage>();
        if(content == null)
            return null;

        return subLink;
    }

    //Da thay doi ham nay.
    public void writeToFile(String dst) {
        String fullPath = getFullPath(dst);
        try {
            File fout = new File(fullPath);
            if(fout.exists())
                return;

            String strFileExtension = getFileExtension();
            if(strFileExtension.equalsIgnoreCase("css") ||
                    strFileExtension.equalsIgnoreCase("js")){
                //resource is css or js file:
                //System.out.println("Test: css, js file:" + fullPath);
                BufferedInputStream in = (BufferedInputStream)getResource();
                BufferedWriter bw = new BufferedWriter(new FileWriter(fout));

                content = getContent(in);
                srcList = getSubResources(strFileExtension);
                //subLinks = getSubLinks(strFileExtension);

                bw.write(content.toString());
                //Download sub resource ?.
                for(Resource src: srcList){
                    src.writeToFile(dst);
                }

                in.close();
                bw.close();
            }else{
                //resource is not css or js file.
                //System.out.println("Test: # css, js file:" + fullPath);
                BufferedInputStream in = (BufferedInputStream)getResource();
                BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(fout));

                byte[] bytes = new byte[1024];
                int nbyte = in.read(bytes, 0, bytes.length);
                while(nbyte != -1) {
                    out.write(bytes, 0, nbyte);
                    nbyte = in.read(bytes, 0, bytes.length);
                }
                out.close();
                in.close();
            }
        } catch (Exception e) {
            return;
        }
    }
}